﻿using System;
using System.ServiceModel.Channels;
using System.Threading.Tasks;
using System.Transactions;
using RockBus.DataContracts;
using RockBus.Messages;
using RockBus.Messages.Interfaces;
using RockBus.Routing.Interfaces;
using RockBus.ServiceModel;

namespace RockBus.Routing.MessageConverters
{
    public class MessageConverter : IMessageConverter
    {
        public IRoutingContext CreateRoutingContext(Guid correlationId, Message message, Transaction transaction, TaskCompletionSource<Message> tcs, ExchangeTypeEnum exchangeType)
        {
            var messageWrapper = new BufferedMessage(message, true);
            return new RoutingContext(correlationId, messageWrapper, transaction, tcs, exchangeType);
        }

        public IRoutingContext CreateRoutingContext(Message message, Transaction transaction, TaskCompletionSource<Message> tcs, ExchangeTypeEnum exchangeType, out RoutingHeader routingHeader)
        {
            routingHeader = null;

            int messageHeaderIndex = message.Headers.FindHeader(RoutingHeader.HeaderName, StringConstants.RockBusNamespace);
            if (messageHeaderIndex >= 0)
            {
                routingHeader = message.Headers.GetHeader<RoutingHeader>(messageHeaderIndex);
                message.Headers.RemoveAt(messageHeaderIndex);
            }

            var correlationId = Guid.NewGuid();
            if (routingHeader != null)
            {
                correlationId = routingHeader.CorrelationId;
            }

            return this.CreateRoutingContext(correlationId, message, transaction, tcs, exchangeType);
        }

        public IRoutingContext CreateRoutingContext(IRoutingContext routingContext, Message message)
        {
            var messageWrapper = new BufferedMessage(message, true);
            return this.CreateRoutingContext(routingContext, messageWrapper);
        }

        public IRoutingContext CreateRoutingContext(IRoutingContext routingContext, IMessage message)
        {
            var newRoutingContext = routingContext.Copy(message);
            return newRoutingContext;
        }

        public Message CreateMessage(IRoutingContext routingContext, RoutingHeader routingHeader, bool addRoutingHeader = false)
        {
            Message message = routingContext.MessageWrapper.Message;

            if ((null != routingHeader) && addRoutingHeader)
            {
                MessageHeader header = MessageHeader.CreateHeader(
                    RoutingHeader.HeaderName,
                    StringConstants.RockBusNamespace,
                    routingHeader);
                message.Headers.Add(header);
            }

            return message;
        }
    }
}
